package com.yunyi.service;

import com.alibaba.fastjson2.JSON;
import com.yunyi.contants.AudioConstants;
import com.yunyi.entity.EndRequest;
import com.yunyi.entity.InitialRequest;
import com.yunyi.socket.MyWebSocketHandler;
import com.yunyi.utils.FileStreamUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.socket.BinaryMessage;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.client.WebSocketClient;
import org.springframework.web.socket.client.standard.StandardWebSocketClient;

import java.io.FileInputStream;
import java.io.IOException;
import java.net.URI;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;

@Service
@Slf4j
public class AudioProcessingService {

    static int chunkInterval = 10;

    static int sendChunkSize = 1920;

    static int RATE = AudioConstants.AUDIO_FS;

    @Value("${websocket.server.url}")
    private String websocketUrl;

    public String processAudio(MultipartFile file) {
        WebSocketClient client = new StandardWebSocketClient();
        MyWebSocketHandler handler = new MyWebSocketHandler();
        WebSocketSession session = null;

        try {
            // 1. 建立WebSocket连接（同步等待连接成功）
            session = client.doHandshake(handler, null, new URI(websocketUrl)).get();


            // 3. 发送初始请求
            InitialRequest initialRequest = this.sendInitialRequest(session, file);

            // 4. 发送音频文件内容
            this.sendAudioData(session, file);

            // 5. 发送结束标识
            this.sendEndRequest(session, initialRequest);

            // 6. 等待服务端响应（带超时机制）
            return handler.getResponse();

        } catch (Exception e) {
            log.error("音频处理失败", e);
            throw new RuntimeException("处理失败: " + e.getMessage());
        } finally {
            closeSession(session);
        }
    }

    private InitialRequest sendInitialRequest(WebSocketSession session, MultipartFile file)
            throws IOException {
        InitialRequest initRequest = new InitialRequest();
        String originalFilename = file.getOriginalFilename();
        initRequest.setWavName(originalFilename);
        String[] split = originalFilename.split("\\.");
        String last = split[split.length - 1];
        if ("wav".endsWith(last)) {
            initRequest.setWavFormat("pcm");
        } else {
            initRequest.setWavFormat(last);
        }
        Map<String, Integer> hotWordsMap = new HashMap<String, Integer>() {
            {
                put("阿里巴巴", 20);
                put("通义实验室", 30);
            }
        };

        int intChunkSize = 60 * initRequest.getChunkSize().get(1) / chunkInterval;
        int chunk = Integer.valueOf(RATE / 1000 * intChunkSize);
        int stride =
                Integer.valueOf(
                        60 * initRequest.getChunkSize().get(1) / chunkInterval / 1000 * 16000 * 2);
        sendChunkSize = chunk * 2;

        initRequest.setHotWords(JSON.toJSONString(hotWordsMap));
        String jsonStr = JSON.toJSONString(initRequest);
        log.info("发送初始请求:{}", jsonStr);
        session.sendMessage(new TextMessage(jsonStr));
        log.info("已发送初始化请求");
        return initRequest;
    }

    private void sendAudioData(WebSocketSession session, MultipartFile file)
            throws IOException, InterruptedException {
        String originalFilename = file.getOriginalFilename();
        int chunkSize = sendChunkSize;
        int readSize = 0;
        byte[] bytes = new byte[chunkSize];
        try (FileInputStream fis = FileStreamUtils.convertMultipartFileToInputStream(file)) {
            if (originalFilename.endsWith(".wav")) {
                fis.read(bytes, 0, 44); //skip first 44 wav header
            }
            readSize = fis.read(bytes, 0, chunkSize);
            while (readSize > 0) {
                // send when it is chunk size
                if (readSize == chunkSize) {
                    ByteBuffer audioByteBuffer = ByteBuffer.wrap(bytes);
                    BinaryMessage binaryMessage = new BinaryMessage(audioByteBuffer);
                    session.sendMessage(binaryMessage);
                } else {
                    // send when at last or not is chunk size
                    byte[] tmpBytes = new byte[readSize];
                    System.arraycopy(bytes, 0, tmpBytes, 0, readSize);
                    ByteBuffer audioByteBuffer = ByteBuffer.wrap(tmpBytes);
                    BinaryMessage binaryMessage = new BinaryMessage(audioByteBuffer);
                    session.sendMessage(binaryMessage);
                }
                readSize = fis.read(bytes, 0, chunkSize);
            }
        }
        log.info("已发送音频数据，大小: {} bytes", file.getSize());
        Thread.sleep(Integer.valueOf(chunkSize / 32));
    }

    private void sendEndRequest(WebSocketSession session, InitialRequest request)
            throws IOException {
        EndRequest endRequest = new EndRequest();
        endRequest.setChunkInterval(request.getChunkInterval());
        endRequest.setChunkSize(request.getChunkSize());
        endRequest.setMode(request.getMode());
        endRequest.setWavName(request.getWavName());
        String jsonStr = JSON.toJSONString(endRequest);
        session.sendMessage(new TextMessage(jsonStr));
        log.info("已发送结束标识,{}", jsonStr);
    }

    private void closeSession(WebSocketSession session) {
        try {
            if (session != null && session.isOpen()) {
                session.close();
                log.info("WebSocket连接已关闭");
            }
        } catch (IOException e) {
            log.warn("关闭连接时发生异常", e);
        }
    }


}